package com.stox.shared.charting.model;

import java.util.ArrayList;
import java.util.List;

import com.stox.shared.core.model.Bar;

public class Kagi extends Bar {

	private final boolean up;
	private final List<Bar> bars = new ArrayList<Bar>();
	private final double reversalSize;
	private final Kagi previousKagi;
	private double trendReversalPrice;
	private boolean previousTrendUp;
	private boolean nextTrendUp;

	public Kagi(final boolean up, final double reversalSize, final Kagi previousKagi) {
		this.up = up;
		this.reversalSize = reversalSize;
		this.previousKagi = previousKagi;
	}

	private boolean processed = false;

	private void process() {
		if (processed) {
			return;
		}
		if (null == previousKagi) {
			trendReversalPrice = -1;
			previousTrendUp = up;
			nextTrendUp = up;
		} else {
			previousTrendUp = previousKagi.nextTrendUp;
			if (up) {
				if ((previousKagi.getHigh() < getHigh()) && (previousKagi.getHigh() > getLow())) {
					trendReversalPrice = previousKagi.getHigh();
					nextTrendUp = up; // true
				} else {
					trendReversalPrice = -1;
					nextTrendUp = previousTrendUp;
				}
			} else {
				if ((previousKagi.getLow() > getLow()) && (previousKagi.getLow() < getHigh())) {
					trendReversalPrice = previousKagi.getLow();
					nextTrendUp = up; // false
				} else {
					trendReversalPrice = -1;
					nextTrendUp = previousTrendUp;
				}
			}
		}
		processed = true;
	}

	public boolean isUp() {
		return up;
	}

	public boolean isPreviousTrendUp() {
		process();
		return previousTrendUp;
	}

	public boolean isNextTrendUp() {
		process();
		return nextTrendUp;
	}

	public Kagi consume(final Bar bar) {
		final double value = getValue(bar);
		if ((up && (value > (getHigh() - reversalSize))) || (!up && (value < (getLow() + reversalSize)))) {
			doConsume(bar);
			return this;
		} else {
			final Kagi kagi = new Kagi(!up, reversalSize, this);
			kagi.setHigh(up ? getHigh() : value);
			kagi.setLow(up ? value : getLow());
			return kagi.consume(bar);
		}
	}

	public double getPreviousReversalPrice() {
		process();
		return trendReversalPrice;
	}

	private void doConsume(final Bar bar) {
		final double value = getValue(bar);
		if (0 == getOpen()) {
			setOpen(value);
		}
		if (up) {
			setHigh(Math.max(getHigh(), value));
		} else {
			setLow(Math.min(getLow(), value));
		}
		if ((0 == getClose()) || ((value <= getHigh()) && (value >= getLow()))) {
			setClose(value);
		}
		setVolume(getVolume() + bar.getVolume());
		setDate(bar.getDate());
		bars.add(bar);
	}

	private double getValue(final Bar bar) {
		return bar.getClose();
	}


	public Kagi getPreviousKagi() {
		return previousKagi;
	}
}
